home *** CD-ROM | disk | FTP | other *** search
/ Giga Games 1 / Giga Games.iso / net / hack / 3_1 / win / x11 / winstat.c < prev    next >
Encoding:
C/C++ Source or Header  |  1993-01-06  |  24.4 KB  |  888 lines

  1. /*    SCCS Id: @(#)winstat.c    3.1    92/3/7
  2. /* Copyright (c) Dean Luick, 1992                  */
  3. /* NetHack may be freely redistributed.  See license for details. */
  4.  
  5. /*
  6.  * Status window routines.  This file supports both the "traditional"
  7.  * tty status display and a "fancy" status display.  A tty status is
  8.  * made if a popup window is requested, otherewise a fancy status is
  9.  * made.  This code assumes that only one fancy status will ever be made.
  10.  * Currently, only one status window (of any type) is _ever_ made.
  11.  */
  12. #include <X11/Intrinsic.h>
  13. #include <X11/StringDefs.h>
  14. #include <X11/Shell.h>
  15. #include <X11/Xaw/AsciiText.h>
  16. #include <X11/Xaw/Cardinals.h>
  17. #include <X11/Xaw/Form.h>
  18. #include <X11/Xaw/Label.h>
  19.  
  20. #include "hack.h"
  21. #include "winX.h"
  22.  
  23. extern const char *hu_stat[]; /* from eat.c */
  24. extern const char *enc_stat[]; /* from botl.c */
  25.  
  26. static void update_fancy_status();
  27. static Widget create_fancy_status();
  28.  
  29. void
  30. create_status_window(wp, create_popup, parent)
  31.     struct xwindow *wp;            /* window pointer */
  32.     boolean create_popup;
  33.     Widget parent;
  34. {
  35.     XFontStruct *fs;
  36.     Arg args[8];
  37.     Cardinal num_args;
  38.     Position top_margin, bottom_margin, left_margin, right_margin;
  39.  
  40.     wp->type = NHW_STATUS;
  41.  
  42.     if (!create_popup) {
  43.     /*
  44.      * If we are not creating a popup, then we must be the "main" status
  45.      * window.
  46.      */
  47.     if (!parent)
  48.         panic("create_status_window: no parent for fancy status");
  49.     wp->status_information = 0;
  50.     wp->w = create_fancy_status(parent, (Widget) 0);
  51.     return;
  52.     }
  53.  
  54.     wp->status_information =
  55.         (struct status_info_t *) alloc(sizeof(struct status_info_t));
  56.  
  57.     init_text_buffer(&wp->status_information->text);
  58.  
  59.     num_args = 0;
  60.     XtSetArg(args[num_args], XtNallowShellResize, False); num_args++;
  61.     XtSetArg(args[num_args], XtNinput, False);            num_args++;
  62.  
  63.     wp->popup = parent = XtCreatePopupShell("status_popup",
  64.                     topLevelShellWidgetClass,
  65.                     toplevel, args, num_args);
  66.  
  67.     num_args = 0;
  68.     XtSetArg(args[num_args], XtNdisplayCaret, False); num_args++;
  69.     XtSetArg(args[num_args], XtNscrollHorizontal,
  70.                     XawtextScrollWhenNeeded);    num_args++;
  71.     XtSetArg(args[num_args], XtNscrollVertical,
  72.                     XawtextScrollWhenNeeded);    num_args++;
  73.  
  74.     wp->w = XtCreateManagedWidget(
  75.         "status",        /* name */
  76.         asciiTextWidgetClass,
  77.         parent,            /* parent widget */
  78.         args,            /* set some values */
  79.         num_args);        /* number of values to set */
  80.  
  81.     /*
  82.      * Adjust the height and width of the message window so that it
  83.      * is two lines high and COLNO of the widest characters wide.
  84.      */
  85.  
  86.     /* Get the font and margin information. */
  87.     num_args = 0;
  88.     XtSetArg(args[num_args], XtNfont,          &fs);           num_args++;
  89.     XtSetArg(args[num_args], XtNtopMargin,    &top_margin);    num_args++;
  90.     XtSetArg(args[num_args], XtNbottomMargin, &bottom_margin); num_args++;
  91.     XtSetArg(args[num_args], XtNleftMargin,   &left_margin);   num_args++;
  92.     XtSetArg(args[num_args], XtNrightMargin,  &right_margin);  num_args++;
  93.     XtGetValues(wp->w, args, num_args);
  94.  
  95.     /* font height is ascent + descent */
  96.     wp->pixel_height = 2 * (fs->ascent + fs->descent) +
  97.                         top_margin + bottom_margin;
  98.     wp->pixel_width  = COLNO * fs->max_bounds.width +
  99.                         left_margin + right_margin;
  100.  
  101.     /* Set the new width and height. */
  102.     num_args = 0;
  103.     XtSetArg(args[num_args], XtNwidth,  wp->pixel_width);  num_args++;
  104.     XtSetArg(args[num_args], XtNheight, wp->pixel_height); num_args++;
  105.     XtSetValues(wp->w, args, num_args);
  106. }
  107.  
  108. void
  109. destroy_status_window(wp)
  110.     struct xwindow *wp;
  111. {
  112.     /* If status_information is defined, then it a "text" status window. */
  113.     if (wp->status_information) {
  114.     nh_XtPopdown(wp->popup);
  115.     XtDestroyWidget(wp->popup);
  116.     free((char *) wp->status_information);
  117.     }
  118.     wp->type = NHW_NONE;
  119. }
  120.  
  121.  
  122. /*
  123.  * This assumes several things:
  124.  *    + Status has only 2 lines
  125.  *    + That both lines are updated in succession in line order.
  126.  *    + We didn't set stringInPlace on the widget.
  127.  */
  128. void
  129. adjust_status(wp, str)
  130.     struct xwindow *wp;
  131.     const char *str;
  132. {
  133.     Arg args[2];
  134.     Cardinal num_args;
  135.  
  136.     if (!wp->status_information) {
  137.     update_fancy_status(wp);
  138.     return;
  139.     }
  140.  
  141.     if (wp->cursy == 0) {
  142.     clear_text_buffer(&wp->status_information->text);
  143.     append_text_buffer(&wp->status_information->text, str, FALSE);
  144.     return;
  145.     }
  146.     append_text_buffer(&wp->status_information->text, str, FALSE);
  147.  
  148.     /* Set new buffer as text. */
  149.     num_args = 0;
  150.     XtSetArg(args[num_args], XtNstring, wp->status_information->text.text);
  151.                                     num_args++;
  152.     XtSetValues(wp->w, args, num_args);
  153. }
  154.  
  155.  
  156. /* Fancy Status -------------------------------------------------------------*/
  157. static Widget init_info_form();
  158. static Widget init_column();
  159. static void set_widths();
  160. static void get_widths();
  161. static void create_widget();
  162. static const char *width_string();
  163. static void hilight_label();
  164. static void update_val();
  165.  
  166. static int hilight_time = 1;    /* number of turns to hilight a changed value */
  167.  
  168. struct X_status_value {
  169.     char    *name;        /* text name */
  170.     int     type;        /* status type */
  171.     Widget  w;            /* widget of name/value pair */
  172.     int     last_value;        /* value displayed */
  173.     int        turn_count;        /* last time the value changed */
  174.     boolean set;        /* if hilighed */
  175.     boolean after_init;        /* don't hilight on first change (init) */
  176. };
  177.  
  178. /* valid type values */
  179. #define SV_VALUE 0    /* displays a label:value pair */
  180. #define SV_LABEL 1    /* displays a changable label */
  181. #define SV_NAME  2    /* displays an unchangeable name */
  182.  
  183. /*
  184.  * Form entry storage indices.
  185.  */
  186. #define F_STR        0
  187. #define F_DEX        1
  188. #define F_CON        2
  189. #define F_INT        3
  190. #define F_WIS        4
  191. #define F_CHA        5
  192.  
  193. #define F_NAME      6
  194. #define F_DLEVEL    7
  195. #define F_GOLD      8
  196. #define F_HP        9
  197. #define F_MAXHP       10
  198. #define F_POWER    11
  199. #define F_MAXPOWER 12
  200. #define F_AC       13
  201. #define F_LEVEL    14
  202. #define F_EXP      15
  203. #define F_ALIGN       16
  204. #define F_TIME     17
  205.  
  206. #define F_HUNGER   18
  207. #define F_CONFUSED 19
  208. #define F_SICK       20
  209. #define F_BLIND       21
  210. #define F_STUNNED  22
  211. #define F_HALLU    23
  212. #define F_ENCUMBER 24
  213.  
  214. #define NUM_STATS  25
  215.  
  216. /*
  217.  * Notes:
  218.  * + Alignment needs a different init value, because -1 is an alignment.
  219.  * + Blank value is 0 and should never change.
  220.  */
  221. static struct X_status_value shown_stats[NUM_STATS] = {
  222.     { "Strength",    SV_VALUE, (Widget) 0, -1, 0, FALSE, FALSE },    /* 0*/
  223.     { "Dexerity",    SV_VALUE, (Widget) 0, -1, 0, FALSE, FALSE },
  224.     { "Constitution",    SV_VALUE, (Widget) 0, -1, 0, FALSE, FALSE },
  225.     { "Intelligence",    SV_VALUE, (Widget) 0, -1, 0, FALSE, FALSE },
  226.     { "Wisdom",        SV_VALUE, (Widget) 0, -1, 0, FALSE, FALSE },
  227.     { "Charisma",    SV_VALUE, (Widget) 0, -1, 0, FALSE, FALSE },    /* 5*/
  228.  
  229.     { "",        SV_LABEL, (Widget) 0, -1, 0, FALSE, FALSE }, /* name */
  230.     { "",        SV_LABEL, (Widget) 0, -1, 0, FALSE, FALSE }, /* dlvl */
  231.     { "Gold",        SV_VALUE, (Widget) 0, -1, 0, FALSE, FALSE },
  232.     { "Hit Points",    SV_VALUE, (Widget) 0, -1, 0, FALSE, FALSE },
  233.     { "Max HP",        SV_VALUE, (Widget) 0, -1, 0, FALSE, FALSE },    /*10*/
  234.     { "Power",        SV_VALUE, (Widget) 0, -1, 0, FALSE, FALSE },
  235.     { "Max Power",    SV_VALUE, (Widget) 0, -1, 0, FALSE, FALSE },
  236.     { "Armor Class",    SV_VALUE, (Widget) 0, -1, 0, FALSE, FALSE },
  237.     { "Level",        SV_VALUE, (Widget) 0, -1, 0, FALSE, FALSE },
  238.     { "Experience",    SV_VALUE, (Widget) 0, -1, 0, FALSE, FALSE },    /*15*/
  239.     { "Alignment",    SV_VALUE, (Widget) 0, -2, 0, FALSE, FALSE },
  240.     { "Time",        SV_VALUE, (Widget) 0, -2, 0, FALSE, FALSE },
  241.  
  242.     { "",        SV_NAME,  (Widget) 0,  0, 0, FALSE, TRUE }, /* hunger*/
  243.     { "Confused",    SV_NAME,  (Widget) 0,  1, 0, FALSE, TRUE },
  244.     { "Sick",        SV_NAME,  (Widget) 0,  0, 0, FALSE, TRUE },    /*20*/
  245.     { "Blind",        SV_NAME,  (Widget) 0,  0, 0, FALSE, TRUE },
  246.     { "Stunned",    SV_NAME,  (Widget) 0,  0, 0, FALSE, TRUE },
  247.     { "Hallucinating",    SV_NAME,  (Widget) 0,  0, 0, FALSE, TRUE },
  248.     { "",        SV_NAME,  (Widget) 0,  0, 0, FALSE, TRUE }, /*encumbr*/
  249.  
  250. };
  251.  
  252.  
  253. /*
  254.  * Set all widget values to a null string.  This is used after all spacings
  255.  * have been calculated so that when the window is popped up we don't get all
  256.  * kinds of funny values being displayed.
  257.  */
  258. void
  259. null_out_status()
  260. {
  261.     int i;
  262.     struct X_status_value *sv;
  263.     Arg args[1];
  264.  
  265.     for (i = 0, sv = shown_stats; i < NUM_STATS; i++, sv++) {
  266.     switch (sv->type) {
  267.         case SV_VALUE:
  268.         set_value(sv->w, "");
  269.         break;
  270.  
  271.         case SV_LABEL:
  272.         case SV_NAME:
  273.         XtSetArg(args[0], XtNlabel, "");
  274.         XtSetValues(sv->w, args, ONE);
  275.         break;
  276.  
  277.         default:
  278.         impossible("null_out_status: unknown type %d\n", sv->type);
  279.         break;
  280.     }
  281.     }
  282. }
  283.  
  284. /* This is almost an exact duplicate of hilight_value() */
  285. static void
  286. hilight_label(w)
  287.     Widget w;    /* label widget */
  288. {
  289.     Arg args[2];
  290.     Pixel fg, bg;
  291.  
  292.     XtSetArg(args[0], XtNforeground, &fg);
  293.     XtSetArg(args[1], XtNbackground, &bg);
  294.     XtGetValues(w, args, TWO);
  295.  
  296.     XtSetArg(args[0], XtNforeground, bg);
  297.     XtSetArg(args[1], XtNbackground, fg);
  298.     XtSetValues(w, args, TWO);
  299. }
  300.  
  301.  
  302. static void
  303. update_val(attr_rec, new_value)
  304.     struct X_status_value *attr_rec;
  305.     long new_value;
  306. {
  307.     char buf[BUFSZ];
  308.     Arg args[4];
  309.  
  310.     if (attr_rec->type == SV_LABEL) {
  311.  
  312.     if (attr_rec == &shown_stats[F_NAME]) {
  313.  
  314.         Strcpy(buf, plname);
  315.         if ('a' <= buf[0] && buf[0] <= 'z') buf[0] += 'A'-'a';
  316.         Strcat(buf, " the ");
  317. #ifdef POLYSELF
  318.         if (u.mtimedone) {
  319.         char mname[BUFSZ];
  320.         int k = 0;
  321.  
  322.         Strcpy(mname, mons[u.umonnum].mname);
  323.         while(mname[k] != 0) {
  324.             if ((k == 0 || (k > 0 && mname[k-1] == ' ')) &&
  325.                     'a' <= mname[k] && mname[k] <= 'z')
  326.                 mname[k] += 'A' - 'a';
  327.             k++;
  328.         }
  329.         Strcat(buf, mname);
  330.         } else
  331. #endif
  332.         Strcat(buf, rank_of(u.ulevel, pl_character[0], flags.female));
  333.  
  334.     } else if (attr_rec == &shown_stats[F_DLEVEL]) {
  335.         if (In_endgame(&u.uz)) {
  336.         Strcpy(buf, (Is_astralevel(&u.uz) ? "Astral Plane":"End Game"));
  337.         } else {
  338.         Strcpy(buf, dungeons[u.uz.dnum].dname);
  339.         Sprintf(eos(buf), ", level %d", depth(&u.uz));
  340.         }
  341.     } else {
  342.         impossible("update_val: unknown label type \"%s\"",
  343.                             attr_rec->name);
  344.         return;
  345.     }
  346.  
  347.     if (strcmp(buf, attr_rec->name) == 0) return;    /* same */
  348.  
  349.     /* Set the label. */
  350.     Strcpy(attr_rec->name, buf);
  351.     XtSetArg(args[0], XtNlabel, buf);
  352.     XtSetValues(attr_rec->w, args, ONE);
  353.  
  354.     } else if (attr_rec->type == SV_NAME) {
  355.  
  356.     if (attr_rec->last_value == new_value) return;    /* no change */
  357.  
  358.     attr_rec->last_value = new_value;
  359.  
  360.     /* special cases: hunger and encumbrance */
  361.     if (attr_rec == &shown_stats[F_HUNGER]) {
  362.         XtSetArg(args[0], XtNlabel, hu_stat[new_value]);
  363.     } else if (attr_rec == &shown_stats[F_ENCUMBER]) {
  364.         XtSetArg(args[0], XtNlabel, enc_stat[new_value]);
  365.     } else if (new_value) {
  366.         XtSetArg(args[0], XtNlabel, attr_rec->name);
  367.     } else {
  368.         XtSetArg(args[0], XtNlabel, "");
  369.     }
  370.     XtSetValues(attr_rec->w, args, ONE);
  371.  
  372.     } else {    /* a value pair */
  373.     boolean force_update = FALSE;
  374.  
  375.     /* special case: time can be enabled & disabled */
  376.     if (attr_rec == &shown_stats[F_TIME]) {
  377.         static boolean flagtime = TRUE;
  378.  
  379.         if(flags.time && !flagtime) {
  380.         set_name(attr_rec->w, shown_stats[F_TIME].name);
  381.         force_update = TRUE;
  382.         flagtime = flags.time;
  383.         } else if(!flags.time && flagtime) {
  384.         set_name(attr_rec->w, "");
  385.         set_value(attr_rec->w, "");
  386.         flagtime = flags.time;
  387.         }
  388.         if(!flagtime) return;
  389.     }
  390. #ifdef POLYSELF
  391.     /* special case: when polymorphed, show "HD", disable exp */
  392.     else if (attr_rec == &shown_stats[F_LEVEL]) {
  393.         static boolean lev_was_poly = FALSE;
  394.  
  395.         if (u.mtimedone && !lev_was_poly) {
  396.         force_update = TRUE;
  397.         set_name(attr_rec->w, "HD");
  398.         lev_was_poly = TRUE;
  399.         } else if (!u.mtimedone && lev_was_poly) {
  400.         force_update = TRUE;
  401.         set_name(attr_rec->w, shown_stats[F_LEVEL].name);
  402.         lev_was_poly = FALSE;
  403.         }
  404.     } else if (attr_rec == &shown_stats[F_EXP]) {
  405.         static boolean exp_was_poly = FALSE;
  406.  
  407.         if (u.mtimedone && !exp_was_poly) {
  408.         force_update = TRUE;
  409.         set_name(attr_rec->w, "");
  410.         set_value(attr_rec->w, "");
  411.         exp_was_poly = TRUE;
  412.         } else if (!u.mtimedone && exp_was_poly) {
  413.         force_update = TRUE;
  414.         set_name(attr_rec->w, shown_stats[F_EXP].name);
  415.         exp_was_poly = FALSE;
  416.         }
  417.         if (u.mtimedone) return;    /* no display for exp when poly */
  418.     }
  419. #endif
  420.  
  421.     if (attr_rec->last_value == new_value && !force_update)    /* same */
  422.         return;
  423.  
  424.     attr_rec->last_value = new_value;
  425.  
  426.     /* Special cases: strength, alignment and "clear". */
  427.     if (attr_rec == &shown_stats[F_STR]) {
  428.         if(new_value > 18) {
  429.         if (new_value > 118)
  430.             Sprintf(buf,"%d", new_value-100);
  431.         else if(new_value < 118)
  432.             Sprintf(buf, "18/%02d", new_value-18);
  433.         else
  434.             Strcpy(buf, "18/**");
  435.         } else {
  436.         Sprintf(buf, "%d", new_value);
  437.         }
  438.     } else if (attr_rec == &shown_stats[F_ALIGN]) {
  439.  
  440.         Strcpy(buf, (new_value == A_CHAOTIC) ? "Chaotic" :
  441.             (new_value == A_NEUTRAL) ? "Neutral" :
  442.                            "Lawful"  );
  443.     } else {
  444.         Sprintf(buf, "%d", new_value);
  445.     }
  446.     set_value(attr_rec->w, buf);
  447.     }
  448.  
  449.     /*
  450.      * Now hilight the changed information.  Names, time and score don't
  451.      * hilight.  If first time, don't hilight.  If already lit, don't do
  452.      * it again.
  453.      */
  454.     if (attr_rec->type != SV_NAME && attr_rec != &shown_stats[F_TIME]) {
  455.     if (attr_rec->after_init) {
  456.         if(!attr_rec->set) {
  457.         if (attr_rec->type == SV_LABEL)
  458.             hilight_label(attr_rec->w);
  459.         else
  460.             hilight_value(attr_rec->w);
  461.         attr_rec->set = TRUE;
  462.         }
  463.         attr_rec->turn_count = 0;
  464.     } else {
  465.         attr_rec->after_init = TRUE;
  466.     }
  467.     }
  468. }
  469.  
  470. /*
  471.  * Update the displayed status.  The current code in botl.c updates
  472.  * two lines of information.  Both lines are always updated one after
  473.  * the other.  So only do our update when we update the second line.
  474.  *
  475.  * Information on the first line:
  476.  *    name, attributes, alignment, score
  477.  *
  478.  * Not done: score
  479.  *
  480.  * Information on the second line:
  481.  *     dlvl, gold, hp, power, ac, {level & exp or HD **}
  482.  *     status (hunger, conf, halu, stun, sick, blind), time, encumbrance
  483.  *
  484.  * [**] HD is shown instead of level and exp if POLYSELF is defined and
  485.  *    mtimedone is non-zero.
  486.  */
  487. static void
  488. update_fancy_status(wp)
  489.     struct xwindow *wp;
  490. {
  491.     const struct X_status_value *sv;
  492.     long val;
  493.     int i;
  494.  
  495.     if (wp->cursy != 0) return;    /* do a complete update when line 0 is done */
  496.  
  497. #ifdef GCC_WARN
  498.     val = 0;
  499. #endif
  500.  
  501.     for (i = 0, sv = shown_stats; i < NUM_STATS; i++, sv++) {
  502.     switch (i) {
  503.         case F_STR:        val = (long) ACURR(A_STR); break;
  504.         case F_DEX:        val = (long) ACURR(A_DEX); break;
  505.         case F_CON:        val = (long) ACURR(A_CON); break;
  506.         case F_INT:        val = (long) ACURR(A_INT); break;
  507.         case F_WIS:        val = (long) ACURR(A_WIS); break;
  508.         case F_CHA:        val = (long) ACURR(A_CHA); break;
  509.         /*
  510.          * Label stats.  With the exceptions of hunger and encumbrance,
  511.          * these are either on or off.  Pleae leave the ternary operators
  512.          * the way they are.  I want to specify 0 or 1, not a boolean.
  513.          */
  514.         case F_HUNGER:    val = (long) u.uhs;            break;
  515.         case F_CONFUSED:    val = (long) Confusion     ? 1L : 0L;    break;
  516.         case F_SICK:    val = (long) Sick       ? 1L : 0L;    break;
  517.         case F_BLIND:    val = (long) Blind       ? 1L : 0L;    break;
  518.         case F_STUNNED:    val = (long) Stunned       ? 1L : 0L;    break;
  519.         case F_HALLU:    val = (long) Hallucination ? 1L : 0L;    break;
  520.         case F_ENCUMBER:    val = (long) near_capacity();        break;
  521.  
  522.         case F_NAME:    val = (long) 0L; break;    /* special */
  523.         case F_DLEVEL:    val = (long) 0L; break;    /* special */
  524.         case F_GOLD:    val = (long) u.ugold; break;
  525. #ifdef POLYSELF
  526.         case F_HP:        val = (long) (u.mtimedone ?
  527.                           (u.mh  > 0 ? u.mh  : 0):
  528.                           (u.uhp > 0 ? u.uhp : 0)); break;
  529.         case F_MAXHP:    val = (long) (u.mtimedone ? u.mhmax :
  530.                                 u.uhpmax);  break;
  531. #else
  532.         case F_HP:        val = (long) (u.uhp > 0 ? u.uhp : 0);    break;
  533.         case F_MAXHP:    val = (long) u.uhpmax;    break;
  534. #endif
  535.         case F_POWER:    val = (long) u.uen;    break;
  536.         case F_MAXPOWER:    val = (long) u.uenmax;    break;
  537.         case F_AC:        val = (long) u.uac;    break;
  538. #ifdef POLYSELF
  539.         case F_LEVEL:    val = (long) (u.mtimedone ?
  540.                         mons[u.umonnum].mlevel :
  541.                         u.ulevel);        break;
  542. #else
  543.         case F_LEVEL:    val = (long) u.ulevel;    break;
  544. #endif
  545.         case F_EXP:        val = (long) u.uexp;    break;
  546.         case F_ALIGN:    val = (long) u.ualign.type; break;
  547.         case F_TIME:    val = flags.time ? (long) moves : 0L;    break;
  548.         default:
  549.         {
  550.         /*
  551.          * There is a possible infinite loop that occurs with:
  552.          *
  553.          *     impossible->pline->flush_screen->bot->bot{1,2}->
  554.          *     putstr->adjust_status->update_other->impossible
  555.          *
  556.          * Break out with this.
  557.          */
  558.         static boolean active = FALSE;
  559.         if (!active) {
  560.             active = TRUE;
  561.             impossible("update_other: unknown shown value");
  562.             active = FALSE;
  563.         }
  564.         break;
  565.         }
  566.     }
  567.     update_val(sv, val);
  568.     }
  569. }
  570.  
  571. /*
  572.  * Turn off hilighted status values after a certain amount of turns.
  573.  */
  574. void
  575. check_turn_events()
  576. {
  577.     int i;
  578.     struct X_status_value *sv;
  579.  
  580.     for (sv = shown_stats, i = 0; i < NUM_STATS; i++, sv++) {
  581.     if (!sv->set) continue;
  582.  
  583.     if (sv->turn_count++ >= hilight_time) {
  584.         if (sv->type == SV_LABEL)
  585.         hilight_label(sv->w);
  586.         else
  587.         hilight_value(sv->w);
  588.         sv->set = FALSE;
  589.     }
  590.     }
  591. }
  592.  
  593. /* Initialize alternate status ============================================= */
  594.  
  595. /* Return a string for the initial width. */
  596. static const char *
  597. width_string(sv_index)
  598.     int sv_index;
  599. {
  600.     switch (sv_index) {
  601.     case F_STR:    return "018/**";
  602.     case F_DEX:
  603.     case F_CON:
  604.     case F_INT:
  605.     case F_WIS:
  606.     case F_CHA:    return "088";    /* all but str never get bigger */
  607.  
  608.     case F_HUNGER:    return shown_stats[F_HUNGER].name;
  609.     case F_CONFUSED:return shown_stats[F_CONFUSED].name;
  610.     case F_SICK:    return shown_stats[F_SICK].name;
  611.     case F_BLIND:    return shown_stats[F_BLIND].name;
  612.     case F_STUNNED: return shown_stats[F_STUNNED].name;
  613.     case F_HALLU:    return shown_stats[F_HALLU].name;
  614.     case F_ENCUMBER:return shown_stats[F_ENCUMBER].name;
  615.  
  616.     case F_NAME:
  617.     case F_DLEVEL:    return "";
  618.     case F_HP:
  619.     case F_MAXHP:    return "9999";
  620.     case F_POWER:
  621.     case F_MAXPOWER:return "999";
  622.     case F_AC:    return "-99";
  623.     case F_LEVEL:    return "99";
  624.     case F_GOLD:
  625.     case F_EXP:    return "4294967295";    /* max ulong */
  626.     case F_ALIGN:    return "Neutral";
  627.     case F_TIME:    return "4294967295";    /* max ulong */
  628.     }
  629.     impossible("width_string: unknown index %d\n", sv_index);
  630.     return "";
  631. }
  632.  
  633. static void
  634. create_widget(parent, sv, sv_index)
  635.     Widget parent;
  636.     struct X_status_value *sv;
  637.     int sv_index;
  638. {
  639.     Arg args[4];
  640.     Cardinal num_args;
  641.  
  642.     switch (sv->type) {
  643.     case SV_VALUE:
  644.         sv->w = create_value(parent, sv->name);
  645.         set_value(sv->w, width_string(sv_index));
  646.         break;
  647.     case SV_LABEL:
  648.         /* Labels get their own buffer. */
  649.         sv->name = (char *) alloc(BUFSZ);
  650.         sv->name[0] = '\0';
  651.  
  652.         num_args = 0;
  653.         XtSetArg(args[num_args], XtNborderWidth, 0);    num_args++;
  654.         XtSetArg(args[num_args], XtNinternalHeight, 0);    num_args++;
  655.         sv->w = XtCreateManagedWidget(
  656.                 sv_index == F_NAME ? "name" : "dlevel",
  657.                 labelWidgetClass,
  658.                 parent,
  659.                 args, num_args);
  660.         break;
  661.     case SV_NAME:
  662.         num_args = 0;
  663.         XtSetArg(args[num_args], XtNborderWidth, 0);    num_args++;
  664.         XtSetArg(args[num_args], XtNinternalHeight, 0);    num_args++;
  665.         sv->w = XtCreateManagedWidget(sv->name,
  666.                     labelWidgetClass,
  667.                     parent,
  668.                     args, num_args);
  669.         break;
  670.     default:
  671.         panic("create_widget: unknown type %d", sv->type);
  672.     }
  673. }
  674.  
  675. /*
  676.  * Get current width of value.  width2p is only valid for SV_LABEL types.
  677.  */
  678. static void
  679. get_widths(sv, width1p, width2p)
  680.     struct X_status_value *sv;
  681.     int *width1p, *width2p;
  682. {
  683.     Arg args[1];
  684.     Dimension width;
  685.  
  686.     switch (sv->type) {
  687.     case SV_VALUE:
  688.         *width1p = get_name_width(sv->w);
  689.         *width2p = get_value_width(sv->w);
  690.         break;
  691.     case SV_LABEL:
  692.     case SV_NAME:
  693.         XtSetArg(args[0], XtNwidth, &width);
  694.         XtGetValues(sv->w, args, ONE);
  695.         *width1p = width;
  696.         *width2p = 0;
  697.         break;
  698.     default:
  699.         panic("get_widths: unknown type %d", sv->type);
  700.     }
  701. }
  702.  
  703. static void
  704. set_widths(sv, width1, width2)
  705.     struct X_status_value *sv;
  706.     int width1, width2;
  707. {
  708.     Arg args[1];
  709.  
  710.     switch (sv->type) {
  711.     case SV_VALUE:
  712.         set_name_width(sv->w, width1);
  713.         set_value_width(sv->w, width2);
  714.         break;
  715.     case SV_LABEL:
  716.     case SV_NAME:
  717.         XtSetArg(args[0], XtNwidth, (width1+width2));
  718.         XtSetValues(sv->w, args, ONE);
  719.         break;
  720.     default:
  721.         panic("set_widths: unknown type %d", sv->type);
  722.     }
  723. }
  724.  
  725. static Widget
  726. init_column(name, parent, top, left, col_indices)
  727.     char *name;
  728.     Widget parent, top, left;
  729.     int *col_indices;
  730. {
  731.     Widget form;
  732.     Arg args[4];
  733.     Cardinal num_args;
  734.     int max_width1, width1, max_width2, width2;
  735.     int *ip;
  736.     struct X_status_value *sv;
  737.  
  738.     num_args = 0;
  739.     if (top != (Widget) 0) {
  740.     XtSetArg(args[num_args], XtNfromVert, top);        num_args++;
  741.     }
  742.     if (left != (Widget) 0) {
  743.     XtSetArg(args[num_args], XtNfromHoriz, left);    num_args++;
  744.     }
  745.     XtSetArg(args[num_args], XtNdefaultDistance, 0);    num_args++;
  746.     form = XtCreateManagedWidget(name,
  747.                 formWidgetClass,
  748.                 parent, args, num_args);
  749.  
  750.     max_width1 = max_width2 = 0;
  751.     for (ip = col_indices; *ip >= 0; ip++) {
  752.     sv = &shown_stats[*ip];
  753.     create_widget(form, sv, *ip);    /* will set init width */
  754.     if (ip != col_indices) {    /* not first */
  755.         num_args = 0;
  756.         XtSetArg(args[num_args], XtNfromVert, shown_stats[*(ip-1)].w);
  757.                                 num_args++;
  758.         XtSetValues(sv->w, args, num_args);
  759.     }
  760.     get_widths(sv, &width1, &width2);
  761.     if (width1 > max_width1) max_width1 = width1;
  762.     if (width2 > max_width2) max_width2 = width2;
  763.     }
  764.     for (ip = col_indices; *ip >= 0 ; ip++) {
  765.     set_widths(&shown_stats[*ip], max_width1, max_width2);
  766.     }
  767.  
  768.     /* There is room behind the end marker for the two widths. */
  769.     *++ip = max_width1;
  770.     *++ip = max_width2;
  771.  
  772.     return form;
  773. }
  774.  
  775. /*
  776.  * These are the orders of the displayed columns.  Change to suit.  The -1
  777.  * indicates the end of the column.  The two numbers after that are used
  778.  * to store widths that are calculated at run-time.
  779.  */
  780. static int attrib_indices[] = { F_STR,F_DEX,F_CON,F_INT,F_WIS,F_CHA, -1,0,0 };
  781. static int status_indices[] = { F_HUNGER, F_CONFUSED, F_SICK, F_BLIND,
  782.                 F_STUNNED, F_HALLU, F_ENCUMBER, -1,0,0 };
  783.  
  784. static int col2_indices[] = { F_MAXHP,F_ALIGN,F_TIME,F_EXP,F_MAXPOWER,-1,0,0 };
  785. static int col1_indices[] = { F_HP, F_AC, F_GOLD, F_LEVEL, F_POWER,   -1,0,0 };
  786.  
  787.  
  788. /*
  789.  * Produce a form that looks like the following:
  790.  *
  791.  *           name
  792.  *          dlevel
  793.  * col1_indices[0]    col2_indices[0]
  794.  * col1_indices[1]    col2_indices[1]
  795.  *    .            .
  796.  *    .            .
  797.  * col1_indices[n]    col2_indices[n]
  798.  */
  799. static Widget
  800. init_info_form(parent, top, left)
  801.     Widget parent, top, left;
  802. {
  803.     Widget form, col1;
  804.     struct X_status_value *sv_name, *sv_dlevel;
  805.     Arg args[6];
  806.     Cardinal num_args;
  807.     int total_width, *ip;
  808.  
  809.     num_args = 0;
  810.     if (top != (Widget) 0) {
  811.     XtSetArg(args[num_args], XtNfromVert, top);    num_args++;
  812.     }
  813.     if (left != (Widget) 0) {
  814.     XtSetArg(args[num_args], XtNfromHoriz, left);    num_args++;
  815.     }
  816.     XtSetArg(args[num_args], XtNdefaultDistance, 0);    num_args++;
  817.     form = XtCreateManagedWidget("status_info",
  818.                 formWidgetClass,
  819.                 parent,
  820.                 args, num_args);
  821.  
  822.     /* top of form */
  823.     sv_name = &shown_stats[F_NAME];
  824.     create_widget(form, sv_name, F_NAME);
  825.  
  826.     /* second */
  827.     sv_dlevel = &shown_stats[F_DLEVEL];
  828.     create_widget(form, sv_dlevel, F_DLEVEL);
  829.  
  830.     num_args = 0;
  831.     XtSetArg(args[num_args], XtNfromVert, sv_name->w);     num_args++;
  832.     XtSetValues(sv_dlevel->w, args, num_args);
  833.  
  834.     /* two columns beneath */
  835.     col1 = init_column("name_col1", form, sv_dlevel->w,
  836.                         (Widget) 0, col1_indices);
  837.     (void) init_column("name_col2", form, sv_dlevel->w,
  838.                               col1, col2_indices);
  839.  
  840.     /* Add calculated widths. */
  841.     for (ip = col1_indices; *ip >= 0; ip++)
  842.     ;    /* skip to end */
  843.     total_width = *++ip;
  844.     total_width += *++ip;
  845.     for (ip = col2_indices; *ip >= 0; ip++)
  846.     ;    /* skip to end */
  847.     total_width += *++ip;
  848.     total_width += *++ip;
  849.  
  850.     XtSetArg(args[0], XtNwidth, total_width);
  851.     XtSetValues(sv_name->w,   args, ONE);
  852.     XtSetArg(args[0], XtNwidth, total_width);
  853.     XtSetValues(sv_dlevel->w, args, ONE);
  854.  
  855.     return form;
  856. }
  857.  
  858. /*
  859.  * Create the layout for the fancy status.  Return a form widget that
  860.  * contains everything.
  861.  */
  862. static Widget
  863. create_fancy_status(parent, top)
  864.     Widget parent, top;
  865. {
  866.     Widget form;    /* The form that surrounds everything. */
  867.     Widget w;
  868.     Arg args[6];
  869.     Cardinal num_args;
  870.  
  871.     num_args = 0;
  872.     if (top != (Widget) 0) {
  873.     XtSetArg(args[num_args], XtNfromVert, top);    num_args++;
  874.     }
  875.     XtSetArg(args[num_args], XtNdefaultDistance, 0);    num_args++;
  876.     XtSetArg(args[num_args], XtNborderWidth, 0);    num_args++;
  877.     form = XtCreateManagedWidget("fancy_status",
  878.                 formWidgetClass,
  879.                 parent,
  880.                 args, num_args);
  881.  
  882.     w = init_info_form(form, (Widget) 0, (Widget) 0);
  883.     w =    init_column("status_attributes",form, (Widget) 0, w, attrib_indices);
  884.     (void) init_column("status_condition", form, (Widget) 0, w, status_indices);
  885.     return form;
  886. }
  887.  
  888.